<?php

class IRouter extends IObject {
	private $standardPath;
	private $router;
	private $base;
	
	public function start() {
		$uri = IRequest::singleton()->uriObj();
		$path = $uri->path();
		
		$controllerName = null;
		$actionName = null;
		
		//从配置中获取controller/action 
		$patterns = IConfig::opt("@router.patterns");
		$params = array();
		if (is_array($patterns)) {
			foreach ($patterns as $pattern) {
				if (preg_match("{" . $pattern["path"] . "}", $path, $match)) {
					foreach ($pattern as $argKey=>$argValue) {								
						if (IVM::singleton()->isValidVariableName($argKey)) {
							if ($argKey == "controller") {
								$argKey = "controllerName";
							}
							if ($argKey == "action") {
								$argKey = "actionName";
							}
							$$argKey = @preg_replace("|\\$(\\d+)|e", "\$match[\\1]", $argValue);
							if (!in_array($argKey, array("controllerName", "actionName", "path"))) {
								$params[$argKey] = $$argKey;
							}
						}
					}					
					break;//找到即跳出
				}
			}
		}
		
		//从查询中获取
		if ($controllerName == null) {
			$request = IRequest::singleton();
			$controllerName = $request->param(IController::controllerKeyword());
			$actionName = $request->param(IController::actionKeyword());
		}
		
		//从路径中获取
		if ($controllerName == null) {
			$trace = debug_backtrace();
			$lastTrace = array_pop($trace);
			$routeFile = basename($lastTrace["file"]);//入口文件
			if (preg_match("/^(.*" . preg_quote($routeFile, "/") . ")(.*)$/U", $path, $match)) {
				$this->base = $match[1];
				$controllerAction = $this->fromPath($match[1], $match[2], $params);
			}
			else if(function_exists("apache_get_modules") && !in_array("mod_rewrite", apache_get_modules())) {//如果不支持重写
				$this->base = rtrim($path, "/") . "/" . $routeFile;
				$controllerAction = $this->fromPath(rtrim($path, "/") . "/" . $routeFile, "/", $params);
			}
			else if (!is_file(".htaccess")) {
				$this->base = rtrim($path, "/") . "/" . $routeFile;
				$controllerAction = $this->fromPath(rtrim($path, "/") . "/" . $routeFile, "/", $params);
			}
			else {//rewrite重写
				$dir = str_replace("\\", "/", dirname($lastTrace["file"]));
				preg_match("/(.+)\|\\1/", $dir . "|" . $path,  $match);
				$base = empty($match)?"" : $match[1];
				$path = preg_replace("/^" . preg_quote($base, "/") . "/", "", $path);
				$this->base = $base;
				$controllerAction = $this->fromPath($base, $path, $params);
			}
			if (!empty($controllerAction)) {
				$controllerName = $controllerAction["controller"];
				$actionName = $controllerAction["action"];
			}
		}
		
		//如果base为null，则设为默认
		if (is_null($this->base)) {
			$this->base = IConfig::opt("@router.base");
		}
		
		if ($controllerName == null) {
			throw new IException("unknown route '{$path}'");
		}
		
		//查找对应的类
		$controller = $this->findController($controllerName, $actionName);
		if ($controller == null) {
			throw new IException("can't find controller class '" . IController::findByName($controllerName) . "' for '{$controllerName}'");
		}
		
		//执行
		$controller->addParams($params);
		$controller->exec();
	}
	
	/**
	 * Enter description here...
	 *
	 * @param unknown_type $controller
	 * @param unknown_type $action
	 * @return Icontroller
	 */
	public function findController($controller, $action) {
		$array = array();
		$array[] = array("controller" => $controller, "action" => $action);// a.b->c
		$array[] = array("controller" => $controller . "." . $action, "action" => IController::defaultAction());//a.b.c->index
		$array[] = array("controller" => $controller . "." . $action . ".index", "action" => IController::defaultAction());//a.b.c.index->index
		foreach ($array as $v) {
			$obj = IController::objByName($v["controller"]);
			if ($obj != null) {
				if (!isInstanceOf($obj, "IController")) {
					throw new IException("controller class '" . get_class($obj) . "' must be from inherited from IController");
				}
				$obj->setRouter($this);
				$obj->setAction($v["action"]);
				$obj->setName($v["controller"]);
				return $obj;
			}
		}
		return null;
	}
	
	public function path($controller, $action) {
		//standard path
		$standardPath = IConfig::opt("@router.standard.path");
		if ($standardPath != null) {
			$this->standardPath = $standardPath;
		}
		$controller = str_replace(".", "/", $controller);
		$action = str_replace(".", "/", $action);
		$path = str_replace("%{controller}", $controller, $this->standardPath);
		$path = str_replace("%{action}", $action, $path);
		
		//alias
		$alias = IConfig::opt("@router.standard.alias");
		if (is_array($alias)) {
			foreach ($alias as $left=>$right) {
				$left = str_replace(array("%{controller}", "%{action}"), array($controller, $action), $left);				
				if ($left == $path) {
					$path = str_replace(array("%{controller}", "%{action}"), array($controller, $action), $right);
				}
			}
		}
		
		return $path;
	}
	
	/**
	 * 尝试从路径中得到控制器
	 *
	 * 尝试把 /a/b/c/d 转换为 a.b.c/d，返回
	 *    array(
	 * 			"controller" => "a.b.c",
	 * 			"action" => "d"
	 *    )
	 * 
	 * 
	 * @param string $baseUrl 基本路径
	 * @param string $path 控制器路径
	 * @return array
	 * @since 0.2.1
	 */
	private function fromPath($baseUrl, $path, &$params) {
		$baseUrl = rtrim($baseUrl, "/");
		$realUrl = trim($path, "/");
		if ($realUrl == "") {
			$this->router = $baseUrl;
			return array("controller" => "index", "action" => IController::defaultAction());
		}
		
		//分解控制器和动作
		$pieces = explode("/", $realUrl);
		if (count($pieces) == 1) {
			//设置路径
			$this->standardPath = $baseUrl . "/%{controller}/%{action}";
			$this->router = $baseUrl;
			return array("controller" => $pieces[0], "action" => IController::defaultAction());
		}
		$last = array_pop($pieces);
		if (preg_match("/^\d+$/", $last)) {
			IRequest::singleton()->addParam("id", $last);
			$params["id"] = $last;
			$action = count($pieces)>1?array_pop($pieces):IController::defaultAction();
		}
		else {
			$action = $last;
		}		
		$this->standardPath = $baseUrl . "/%{controller}/%{action}";
		$this->router = $baseUrl;
		return array("controller" => implode(".", $pieces), "action" => $action);
	}
	
	public function base() {
		return $this->base;
	}
}

?>